package de.baumann.browser.api;

import android.accounts.NetworkErrorException;
import android.util.Log;

import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

import javax.net.ssl.SSLHandshakeException;

import de.baumann.browser.OdinApplication;
import de.baumann.browser.R;
import de.baumann.browser.api.net.vo.Result;
import de.baumann.browser.iview.IBaseView;
import de.baumann.browser.utils.NetworkUtils;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import retrofit2.HttpException;

import static de.baumann.browser.utils.Constants.INPUT_DATA_ERROR;
import static de.baumann.browser.utils.Constants.LOGIN_EXPIRED;

/**
 * @author junce
 */
public abstract class OdinObserver<T> implements Observer<Result> {

    private static final int HTTP_OK = 1000;
    private static final int NET_500 = 500;
    private static final int NET_503 = 503;
    private static final int NET_404 = 404;
    private static final String TAG = OdinObserver.class.getSimpleName();

    private IBaseView view;
    private boolean isSowLoading;

    public OdinObserver() {
    }

    public OdinObserver(IBaseView view) {
        this(view, true);
    }

    public OdinObserver(IBaseView view, boolean isSowLoading) {
        this.view = view;
        this.isSowLoading = isSowLoading;
    }

    @Override
    public void onSubscribe(Disposable d) {
        if (view != null && isSowLoading) {
            view.showLoading();
        }
    }

    @Override
    public void onNext(Result result) {
        switch (result.getCode()) {
            case HTTP_OK:
                onSuccess((T) result.getData());
                break;
            case LOGIN_EXPIRED:
                if (view != null) {
                    view.tokenInvalid();
                    view = null;
                }
                break;
            case 1415:
                if (view != null) {
                    view.notEthUrl();
                }
                break;
            case 1400:
                if (view != null) {
                    view.onError(result.getMsg());
                }
                break;
            case 2000:
                break;
            case INPUT_DATA_ERROR:
                onFailed(result.getErrorMsg());
                break;
            default:
                onFailed(result.getCode(), result.getMsg());
        }
    }

    @Override
    public void onError(Throwable e) {
        try {
            if (e instanceof NetworkErrorException) {
                onFailed(R.string.network_is_not_available);
            } else if (e instanceof SocketTimeoutException || e instanceof ConnectException) {
                onFailed(R.string.check_network_is_available);
            } else if (e instanceof SSLHandshakeException) {
                onFailed(R.string.security_certificate_is_abnormal);
            } else if (e instanceof HttpException) {
                int code = ((HttpException) e).code();
                if (code == NET_500) {
                    onFailed(R.string.NET_500);
                } else if (code == NET_503) {
//                    onFailed(R.string.NET_503);
                } else if (code == NET_404) {
                    onFailed(R.string.NET_404);
                } else {
                    onFailed(R.string.request_failed);
                }
            } else if (e instanceof UnknownHostException) {
                if (NetworkUtils.isNetWorkAvailable(OdinApplication.getInstance())) {
                    onFailed(R.string.domain_name_resolution_error);
                } else {
                    onFailed(R.string.network_is_not_available);
                }
            } else {
//                onFailed("error:" + e.getMessage());
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
//            Log.e(TAG, "error:" + e.getMessage());
            onComplete();
        }
    }

    @Override
    public void onComplete() {
        if (isSowLoading && view != null) {
            view.hideLoading();
        }
    }

    /**
     * 处理成功
     *
     * @param data 返回数据
     */
    protected abstract void onSuccess(T data);

    /**
     * 处理失败
     *
     * @param msg 失败原因
     */
    private void onFailed(String msg) {
        if (view != null) {
            view.onError(msg);
        }
    }

    private void onFailed(int msgId) {
        if (view != null) {
            view.onError(msgId);
        }
    }

    /**
     * 处理失败
     *
     * @param code 状态码
     * @param msg  失败原因
     */
    protected void onFailed(int code, String msg) {
        Log.d(TAG, "onFailed: " + msg);
        onFailed(msg);
    }
}
